// This file is part of Module Proxy.

// Module Proxy is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Module Proxy is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Module Proxy.  If not, see <https://www.gnu.org/licenses/>.


//         Copyright (C) 2021 - 2030  关中麦客  
//         All rights reserved
//
//         mod_uuidmap.rs
//         uuid鉴权
//
//         created by 关中麦客 1036038462@qq.com

use std::collections::HashMap;
use tokio::sync::mpsc::{Sender, channel};
use tokio::sync::Mutex; 
use tokio::sync::oneshot;
use once_cell::sync::OnceCell;

//全局 channel tx
static TX: OnceCell<Mutex<Sender<Method>>> = OnceCell::new(); 

/// channel 接口
// #[derive(Debug)]
enum Method
{
    Set 
    {
        uuid:       String,     //auth key
        val:        String,     //auth 值
        timeout:    u32,        //超时秒时间戳
    },
    Get
    {
        uuid:       String,
        rsp:        oneshot::Sender<Option<(String, u32)>>,  
    },
    GetExp  //获得所有失效的uuid
    {
        rsp:        oneshot::Sender<Vec<String>>,
    },
    Del
    {
        uuid:       String,     
    },
}

// 初始化
pub fn init()
{    
    //uuid鉴权非使能（被注释）
    if !super::conf::enable_module_uuid_auth()
    {
        //log::info!("mod_urlmap disabled!");
        return;  
    }

    log::info!("map of mod_uuid init...");

    //初始化channel tx rx
    let (tx, mut rx) = channel(32);

    //初始化缓存
    TX.get_or_init(||{
        Mutex::new(tx)
    });

    //缓存
    let mut _cache: HashMap<String, (String, u32)> = HashMap::new(); 

    //接收任务 ---------------
    tokio::spawn(async move {

        while let Some(method) = rx.recv().await
        {
            match method
            {
                Method::Set{uuid, val, timeout} =>
                {
                    let tup: (String, u32) = (val, timeout);
                     _cache.insert(uuid, tup);
                }
                Method::Get{uuid, rsp} =>
                {
                     if let Some(tup) = _cache.get(&uuid)
                    {
                         //返回
                        let ret_tup: (String, u32) = (tup.0.clone(), tup.1);
                        let _ = rsp.send(Some(ret_tup));
                    }
                    else
                    {
                        let _ = rsp.send(None);
                    }
                }
                Method::GetExp{rsp} =>
                {
                    let mut list: Vec<String> = Vec::new();
                    for (uuid, (_, timeout)) in &_cache
                    {
                        //超时
                        if *timeout < super::util::sec_timestamp()
                        {
                            list.push(uuid.clone());
                        } 
                    }
                    let _ = rsp.send(list);
                }
                Method::Del{uuid} =>
                {
                    log::debug!("[mod_uuidmap] release uuid: {}", &uuid);
                    _cache.remove(&uuid);
                }
            }
        }
    });
}

/// ----------------------------- 接口 ------------------------------

///发送channel消息 set
pub async fn set(uuid: String, val: String, timeout: u32)
{
    if let Some(mutex) = TX.get()
    {
        let tx = mutex.lock().await;
        let tx = tx.clone();
        let method = Method::Set{uuid, val, timeout};
        let _ = tx.send(method).await;        //发送
    }    
}

/// 发送channel消息 get
pub async fn get(uuid: &str) -> Option<(String, u32)>
{
    let (rsp_tx, rsp_rx) = oneshot::channel();
    if let Some(mutex) = TX.get()
    {
        let tx = mutex.lock().await;
        let tx = tx.clone();
        let method = Method::Get{uuid: uuid.to_string(), rsp: rsp_tx};
        let _ = tx.send(method).await;  //发送
        if let Ok(tup) = rsp_rx.await   //接收
        {
            return tup;
        }
    }

    None
}

/// 发送channel消息 get
pub async fn get_exp() -> Vec<String>
{
    let (rsp_tx, rsp_rx) = oneshot::channel();
    if let Some(mutex) = TX.get()
    {
        let tx = mutex.lock().await;
        let tx = tx.clone();
        let method = Method::GetExp{rsp: rsp_tx};
        let _ = tx.send(method).await;  //发送
        if let Ok(list) = rsp_rx.await   //接收
        {
            return list;
        }
    }

    Vec::new()
}

///发送channel消息 del
pub async fn del(uuid: String)
{
    if let Some(mutex) = TX.get()
    {
        let tx = mutex.lock().await;
        let tx = tx.clone();
        let method = Method::Del{uuid};
        let _ = tx.send(method).await;        //发送
    }    
}